﻿/*-------------------------------------------------------------------------
* 命名空间: WaferSelectV3.Common/LoggerHelper
* 类       名: LoggerHelper
* 功      能:  TD
* 时      间:  2024-04-19 10:43:28
* 版      本:  V1.0
* 作      者:  Fioman
* 格      言:  Talk is cheap,show me the code ^_^
*-------------------------------------------------------------------------*/
using log4net;
using log4net.Appender;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WaferSelectV3.Common
{
    public class LoggerHelper
    {
        private static readonly ILog MainLogger;
        private static readonly ILog SizeLogger;
        private static readonly ILog NaponsLogger;
        private static readonly ILog ThreeDLogger;
        private static readonly ILog SmudgeLogger;
        private static readonly ILog SubfissureLogger;
        private static readonly ILog EdgeBreakLogger;
        private static readonly ILog CrashLogger;
        // 异步任务Token管理对象
        public static CancellationTokenSource ClearCts = new CancellationTokenSource();

        // 静态构造函数在类型被第一次使用之前自动被调用,并且只会被调用一次.
        // 这里的使用指的是引用任何静态成员,创建类的实例或者是派生自该类型的类被使用
        static LoggerHelper()
        {
            // 加载log4Net的配置文件(手动加载)
            //log4net.Config.XmlConfigurator.Configure();
            MainLogger = LogManager.GetLogger(@"MainSlaveLogger");
            SizeLogger = LogManager.GetLogger(@"SizeSlaveLogger");
            NaponsLogger = LogManager.GetLogger(@"NaponsLogger");
            ThreeDLogger = LogManager.GetLogger(@"ThreeDLogger");
            SmudgeLogger = LogManager.GetLogger(@"SmudgeLogger");
            SubfissureLogger = LogManager.GetLogger(@"SubfissureLogger");
            EdgeBreakLogger = LogManager.GetLogger(@"EdgeBreakLogger");
            CrashLogger = LogManager.GetLogger(@"CrashLogger");

            // WriteLogMain("LoggerHelper() 构造方法被调用", LogType.Test);

            Task.Run(async () =>
            {
                try
                {
                    while (!ClearCts.Token.IsCancellationRequested)
                    {
                        DoClearOverDueLogs();
                        WriteLogMain("清除过期日志完成.", LogType.Info);
                        // 每隔24小时清理一次,后面加上一个Token的目的就是可以在外部取消这个异步等待任务
                        await Task.Delay(86400000, ClearCts.Token);
                    }
                }
                catch (OperationCanceledException)
                {
                    WriteLogMain("清理过期日志监控任务被取消", LogType.Info);
                }
                catch (Exception ex)
                {
                    WriteLogMain("清理过期日志任务发生异常: " + ex.Message, LogType.Exception);
                }
            });

        }

        /// <summary>
        /// 清理过期日志,从配置文件中获取过期日志的天数
        /// </summary>
        private static void DoClearOverDueLogs()
        {
            // 从配置文件中获取保存日志的天数
            int maxDays = Convert.ToInt32(ConfigurationManager.AppSettings["OverdueDays"]);
            // 如果没有配置的时候maxDays返回的是多少呢.如果上面的OverdueDays没有配置,默认这里是返回0
            int days = maxDays == 0 ? 15 : maxDays;
            // 最小日期
            DateTime latestDay = DateTime.Now.AddDays(-days);
            // 通过LoggerManager获取所有的Appender
            //IAppender[] appenders = LoggerManager.GetRepository(Assembly.GetEntryAssembly()).GetAppenders();
            // 通过Logger对象获取所有的appenders,都是先获取Repository.都是先获取日志仓库,然后获取日志配置文件中已经配置的
            // 的所有的Appender.
            IAppender[] appenders = MainLogger.Logger.Repository.GetAppenders();
            foreach (var append in appenders)
            {
                if (!(append is RollingFileAppender roller))
                {
                    continue;
                }
                string? dir = Path.GetDirectoryName(roller.File);
                string[] files = Directory.GetFiles(dir!, "*.log*");
                foreach (string filePath in files)
                {
                    FileInfo file = new FileInfo(filePath);
                    if (file.CreationTime < latestDay || file.LastWriteTime < latestDay)
                    {
                        try
                        {
                            file.Delete();
                        }
                        catch (Exception ex)
                        {
                            WriteLogMain("日志清理失败: " + ex.Message, LogType.Info);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 最后的写日志的逻辑,根据不同的ILog对象来写具体的Log日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="logType"></param>
        /// <param name="logger"></param>
        private static void WriteLog(string message, LogType logType, ILog logger)
        {
            if (logger != null)
            {
                switch (logType)
                {
                    case LogType.Info:
                        logger.Info(message);
                        break;
                    case LogType.Debug:
                        logger.Debug(message);
                        break;
                    case LogType.Warn:
                        logger.Warn(message);
                        break;
                    case LogType.Exception:
                        logger.Error(message);
                        break;
                    case LogType.Fatal:
                        logger.Fatal(message);
                        break;
                    case LogType.Test:
                        logger.Info($"TestShow: {message}");
                        break;
                }
            }
        }
        // 1. 主站日志记录
        public static void WriteLogMain(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, MainLogger);
        }

        // 2. 3D日志记录
        public static void WriteLog3D(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, ThreeDLogger);
        }

        // 3. 尺寸日志记录
        public static void WriteLogSize(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, SizeLogger);
        }

        // 4. 脏污日志记录
        public static void WriteLogSmudge(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, SmudgeLogger);
        }
        // 5. 隐裂日志记录
        public static void WriteLogSubfissure(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, SubfissureLogger);
        }
        // 6. 崩边日志记录
        public static void WriteLogEdgeBreak(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, EdgeBreakLogger);
        }
        // 7. 电阻率日志记录
        public static void WriteLogNapons(string message, LogType logType = LogType.Info, string errorCode = "")
        {
            WriteLog(message, logType, NaponsLogger);
        }
        // 8. 程序崩溃异常日志记录
        public static void WriteLogCrashes(string message, LogType logType = LogType.Fatal, string errorCode = "")
        {
            WriteLog(message, logType, CrashLogger);
        }

        public static void WriteLogWithClient(string message, string? clientName)
        {
            if (clientName!.Contains("尺寸"))
            {
                WriteLogSize(message);
            }
            else if (clientName!.Contains("3D"))
            {
                WriteLog3D(message);
            }
            else if (clientName!.Contains("崩边隐裂") && message.Contains("Subfi"))
            {
                WriteLogSize(message);
            }
            else if (clientName!.Contains("脏污"))
            {
                WriteLogSmudge(message);
            }
            else if (clientName.Contains("电阻率"))
            {
                WriteLogNapons(message);
            }
            else if (clientName.Contains("主站"))
            {
                WriteLogMain(message);
            }
            else
            {
                WriteLogEdgeBreak(message);
            }
        }
    }

    public enum LogType
    {
        Info,
        Debug,
        Warn,
        Exception,
        Fatal,
        Test,
    }
}
